#include <device/clock.h>
#include <sys/interrupt.h>
#include <sys/io.h>
#include <assert.h>
#include <yonex/debug.h>
#include <stdbool.h>

#define LOGK(fmt, args...)  DEBUGK(fmt, ##args)

#define PIT_CHAN0_REG   0x40
#define PIT_CHAN2_REG   0x42
#define PIT_CTRL_REG    0x43
#define SPEAKER_REG     0x61

#define HZ          100
#define OSCILLATOR  1193182
#define CLOCK_COUNT (OSCILLATOR / HZ)
#define JIFFY       (1000 / HZ)

#define BEEP_HZ     363     // Lucky Number
#define BEEP_COUNT  (OSCILLATOR / BEEP_HZ)

u64 volatile jiffies = 0;   // 时间片计数器
u64 jiffy = JIFFY;
u64 volatile beeping = 0;

void start_beep()
{
    if (!beeping) {
        outb(SPEAKER_REG, (inb(SPEAKER_REG) | 0b00000011));
    }
    beeping = jiffies + 5;
}

void stop_beep()
{
    if ((beeping > 0) && (jiffies > beeping)) {
        outb(SPEAKER_REG, (inb(SPEAKER_REG) & 0b11111100));
        beeping = 0;
    }
}

void clock_handler(int vector)
{
    assert(vector == IRQ_CLOCK);
    send_eoi(vector);

    jiffies++;
    // LOGK("clock jiffies %lu ...\n", jiffies);
    stop_beep();
}

void pit_init()
{
    LOGK("init pit\n");
    // 计数器 0 : 时钟中断
    outb(PIT_CTRL_REG, 0b00110100);
    outb(PIT_CHAN0_REG, (CLOCK_COUNT & 0xff));
    outb(PIT_CHAN0_REG, ((CLOCK_COUNT >> 8) & 0xff));
    // 计数器 1 : 蜂鸣器
    outb(PIT_CTRL_REG, 0b10110110);
    outb(PIT_CHAN2_REG, (BEEP_COUNT & 0xff));
    outb(PIT_CHAN2_REG, ((BEEP_COUNT >> 8) & 0xff));
}

void clock_init()
{
    pit_init();
    set_interrupt_handler(IRQ_CLOCK, clock_handler);
    set_interrupt_mask(IRQ_CLOCK, true);
}
